package cn.ivicar.app.controller.sae;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.web.env.WebEnvironment;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.carsmart.sae.authc.Authenticator;
import cn.com.carsmart.sae.matcher.CredentialsMatcher;
import cn.com.carsmart.sae.matcher.ShiroCredentialsMatcher;
import cn.com.carsmart.sae.realm.ShiroRealm;
import cn.com.carsmart.sae.web.EnvironmentLoader;
import cn.com.carsmart.sae.web.EnvironmentLoaderListener;
import cn.com.carsmart.sae.web.WebUtils;

public class ShiroEnvironmentLoaderListener implements ServletContextListener {

    private static transient final Logger LOGGER = LoggerFactory
            .getLogger(EnvironmentLoaderListener.class);

    private EnvironmentLoader envLoader = new EnvironmentLoader();
    private static final String AUTHC_CLASS_PARAM = "authenticatorClassName";
    private static final String CREDENTIALS_MATCHER_PARAM = "matcherClassName";
    private static final String GLOBAL_SESSION_TIMEOUT = "globalSessionTimeout";

    public void contextInitialized(ServletContextEvent sce) {
        this.envLoader.initEnvironment(sce.getServletContext());
        initSaeEnvironment(sce.getServletContext());
    }

    public void contextDestroyed(ServletContextEvent sce) {
        this.envLoader.destroyEnvironment(sce.getServletContext());
    }

    private void initSaeEnvironment(ServletContext sc) {
        WebEnvironment env = WebUtils.getRequiredWebEnvironment(sc);
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) env
                .getWebSecurityManager();
        /*ShiroWebSessionManager session = new ShiroWebSessionManager();
        session.setSessionIdCookieEnabled(false);
        securityManager.setSessionManager(session);*/

        String globalsessionTimeout = sc.getInitParameter(GLOBAL_SESSION_TIMEOUT);
        if (globalsessionTimeout != null) {
        	ShiroWebSessionManager sessionManager = (ShiroWebSessionManager) securityManager
                    .getSessionManager();
            sessionManager.setGlobalSessionTimeout(Long.getLong(globalsessionTimeout));
        }

        ShiroRealm realm = (ShiroRealm) securityManager.getRealms().iterator().next();
        Authenticator authenticator = getCustomAuthenticator(sc);
        CredentialsMatcher matcher = getCustomMatcher(sc);
        realm.setSaeAuthenticator(authenticator);
        ((ShiroCredentialsMatcher) realm.getCredentialsMatcher())
                .setInternalCredentialsMatcher(matcher);
    }

    private Authenticator getCustomAuthenticator(ServletContext sc) {
        String authcClassName = sc.getInitParameter(AUTHC_CLASS_PARAM);
        if (authcClassName == null) {
            LOGGER.warn("Authenticator未指定");
            return null;
        }

        Class<?> auth = ClassUtils.forName(authcClassName);
        if (auth == null) {
            LOGGER.warn(auth + "未找到");
            return null;
        }

        Authenticator authenticator = (Authenticator) ClassUtils.newInstance(auth);
        return authenticator;
    }

    private CredentialsMatcher getCustomMatcher(ServletContext sc) {
        String matcherClassName = sc.getInitParameter(CREDENTIALS_MATCHER_PARAM);
        if (matcherClassName == null) {
            LOGGER.warn("CredentialsMatcher未指定");
            return null;
        }

        Class<?> matcher = ClassUtils.forName(matcherClassName);
        if (matcher == null) {
            LOGGER.warn(matcher + "未找到");
            return null;
        }

        return (CredentialsMatcher) ClassUtils.newInstance(matcher);
    }
}